#pragma once

#include <functional>
#include "comm.hpp"
#include "Connection.hpp"
#include "Socket.hpp"
#include "Log.hpp"

using namespace SocketModule;

#define SIZE 1024

class Channel : public Connection
{
public:
    Channel(int sockfd, const InetAddr &client) : _sockfd(sockfd),
                                                  _client_addr(client)
    {
        SetNonBlock(sockfd);
    }

    void Recver() override
    {
        LOG(LogLevel::DEBUG) << "事件被派发到了channel模块, sockfd: "
                             << GetFd();
        char buff[SIZE];
        while (true)
        {
            buff[0] = 0;
            ssize_t n = recv(_sockfd, buff, sizeof(buff) - 1, 0);
            if (n > 0)
            {
                buff[n] = 0;
                _inbuffer += buff;
            }
            else if (n == 0)
            {
                Execpter();
                return;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                else if (errno == EINTR)
                {
                    continue;
                }
                else
                {
                    Execpter();
                    return;
                }
            }
        }
        LOG(LogLevel::DEBUG) << "channel: inbuffer: " << _inbuffer;
        if (!_inbuffer.empty())
        {
            _outbuffer += _handler(_inbuffer);
        }
        if (!_outbuffer.empty())
        {
            Sender();
        }
    }

    void Sender() override
    {
        while (true)
        {
            ssize_t n = send(_sockfd, _outbuffer.c_str(), _outbuffer.size(), 0);
            if (n > 0)
            {
                _outbuffer.erase(0, n);
                if (_outbuffer.empty())
                    break;
            }
            else if (n == 0)
            {
                break;
            }
            else
            {
                if (errno == EAGAIN || errno == EWOULDBLOCK)
                {
                    break;
                }
                if (errno == EINTR)
                    continue;
                else
                {
                    Execpter();
                    return;
                }
            }
        }
        if (!_outbuffer.empty())
        {
            // 开启对写事件的关心
            GetOwner()->EnableReadWrite(_sockfd, true, true);
        }
        else
        {
            GetOwner()->EnableReadWrite(_sockfd, true, false);
        }
    }

    void Execpter() override
    {
        GetOwner()->DelConnection(_sockfd);
    }

    void AppendOutBuffer(const std::string &out)
    {
        _outbuffer += out;
    }

    std::string &Inbuffer() { return _inbuffer; }
    int GetFd() override { return _sockfd; }

    ~Channel() {}

private:
    int _sockfd;
    std::string _inbuffer;
    std::string _outbuffer;
    // client info
    InetAddr _client_addr;
};